use anyhow::{Context, Result};
use clap::{Parser, Subcommand, ValueEnum};
use akoption::db::DbConfig;
use tracing_subscriber::{fmt, EnvFilter};

#[derive(Parser, Debug)]
#[command(name = "akoption")] 
#[command(about = "AKShare Options (Rust)", version = "0.1.0")]
struct Cli {
    /// Enable verbose logs
    #[arg(short, long, global = true)]
    verbose: bool,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand, Debug)]
enum Commands {
    /// Finance board by symbol and end-month
    FinanceBoard {
        #[arg(value_enum)]
        symbol: FinanceSymbol,
        /// End month: YYMM or YYYYMM
        end_month: String,
    },
    /// Eastmoney option snapshot (merged with CFFEX)
    EmCurrent,
    /// SSE underlying snapshot
    SseUnderlying {
        #[arg(value_enum)]
        symbol: SseUnderlyingSymbol,
    },
    /// Option value analysis - Eastmoney
    EmValueAnalysis,
    /// Option risk analysis - Eastmoney
    EmRiskAnalysis,
    /// Option premium analysis - Eastmoney
    EmPremiumAnalysis,
    /// Option minute data - Eastmoney
    EmMinute {
        /// Option symbol (e.g., MO2402-C-5400)
        symbol: String,
    },
    /// SSE risk indicator
    SseRiskIndicator {
        /// Trade date (YYYYMMDD)
        date: String,
    },
    /// SSE current day contracts
    SseCurrentDay,
    /// SZSE current day contracts
    SzseCurrentDay,
    /// SSE daily statistics
    SseDailyStats {
        /// Trade date (YYYYMMDD)
        date: String,
    },
    /// SZSE daily statistics
    SzseDailyStats {
        /// Trade date (YYYYMMDD)
        date: String,
    },
    /// CFFEX SZ50 contract list - Sina
    CffexSz50ListSina,
    /// CFFEX SZ50 spot - Sina
    CffexSz50SpotSina {
        /// Contract symbol (e.g., ho2303)
        symbol: String,
    },
    /// CFFEX SZ50 daily - Sina
    CffexSz50DailySina {
        /// Contract symbol (e.g., ho2303)
        symbol: String,
    },
    /// CFFEX HS300 contract list - Sina
    CffexHs300ListSina,
    /// CFFEX HS300 spot - Sina
    CffexHs300SpotSina {
        /// Contract symbol (e.g., mo2303)
        symbol: String,
    },
    /// CFFEX HS300 daily - Sina
    CffexHs300DailySina {
        /// Contract symbol (e.g., mo2303)
        symbol: String,
    },
    /// CFFEX ZZ1000 contract list - Sina
    CffexZz1000ListSina,
    /// CFFEX ZZ1000 spot - Sina
    CffexZz1000SpotSina {
        /// Contract symbol (e.g., io2303)
        symbol: String,
    },
    /// CFFEX ZZ1000 daily - Sina
    CffexZz1000DailySina {
        /// Contract symbol (e.g., io2303)
        symbol: String,
    },
    /// Database commands
    #[command(subcommand)]
    Db(DbCommands),
}

#[derive(Subcommand, Debug)]
enum DbCommands {
    /// Save data to database
    Save {
        /// Data type to save
        #[arg(value_enum)]
        data_type: DataType,
        /// Database path (optional, default: ./data/akoption.db)
        #[arg(short, long)]
        path: Option<String>,
    },
    /// Query data from database
    Query {
        /// Data type to query
        #[arg(value_enum)]
        data_type: DataType,
        /// Optional code filter
        #[arg(short, long)]
        code: Option<String>,
        /// Database path (optional, default: ./data/akoption.db)
        #[arg(short, long)]
        path: Option<String>,
    },
    /// Show database statistics
    Stats {
        /// Database path (optional, default: ./data/akoption.db)
        #[arg(short, long)]
        path: Option<String>,
    },
    /// Clear table data
    Clear {
        /// Table name to clear
        table: String,
        /// Database path (optional, default: ./data/akoption.db)
        #[arg(short, long)]
        path: Option<String>,
    },
}

#[derive(Copy, Clone, Debug, ValueEnum)]
enum DataType {
    /// Eastmoney options
    EmOptions,
    /// Value analysis
    ValueAnalysis,
    /// Risk analysis
    RiskAnalysis,
    /// SSE contracts
    SseContracts,
}

#[derive(Copy, Clone, Debug, ValueEnum)]
enum FinanceSymbol {
    Sse50Etf,
    Sse300Etf,
    Sse500Etf,
    SseKc50Etf,
    SseKc50EtfYfd,
    Szse300Etf,
    CffexIo,
    CffexMo,
    CffexHo,
}

#[derive(Copy, Clone, Debug, ValueEnum)]
enum SseUnderlyingSymbol {
    HuaXia50,
    HuaTai300,
    NanFang500,
    KeChuang50,
    KeChuang50Yfd,
}

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();
    let filter = if cli.verbose { "debug" } else { "info" };
    fmt().with_env_filter(EnvFilter::new(filter)).init();

    match cli.command {
        Commands::FinanceBoard { symbol, end_month } => {
            use akoption::types::{EndMonth, FinanceSymbol as F};
            let end = EndMonth::new(end_month);
            let sym = match symbol {
                FinanceSymbol::Sse50Etf => F::Sse50Etf,
                FinanceSymbol::Sse300Etf => F::Sse300Etf,
                FinanceSymbol::Sse500Etf => F::Sse500Etf,
                FinanceSymbol::SseKc50Etf => F::SseKc50Etf,
                FinanceSymbol::SseKc50EtfYfd => F::SseKc50EtfYfd,
                FinanceSymbol::Szse300Etf => F::Szse300Etf,
                FinanceSymbol::CffexIo => F::CffexIO,
                FinanceSymbol::CffexMo => F::CffexMO,
                FinanceSymbol::CffexHo => F::CffexHO,
            };
            let data = akoption::option_finance_board(sym, end).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::EmCurrent => {
            let data = akoption::option_current_em().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SseUnderlying { symbol } => {
            use akoption::types::SseUnderlying as S;
            let sym = match symbol {
                SseUnderlyingSymbol::HuaXia50 => S::HuaXia50,
                SseUnderlyingSymbol::HuaTai300 => S::HuaTai300,
                SseUnderlyingSymbol::NanFang500 => S::NanFang500,
                SseUnderlyingSymbol::KeChuang50 => S::KeChuang50,
                SseUnderlyingSymbol::KeChuang50Yfd => S::KeChuang50Yfd,
            };
            let data = akoption::option_finance_sse_underlying(sym).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::EmValueAnalysis => {
            let data = akoption::option_value_analysis_em().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::EmRiskAnalysis => {
            let data = akoption::option_risk_analysis_em().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::EmPremiumAnalysis => {
            let data = akoption::option_premium_analysis_em().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::EmMinute { symbol } => {
            let data = akoption::option_minute_em(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SseRiskIndicator { date } => {
            let data = akoption::option_risk_indicator_sse(&date).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SseCurrentDay => {
            let data = akoption::option_current_day_sse().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SzseCurrentDay => {
            let data = akoption::option_current_day_szse().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SseDailyStats { date } => {
            let data = akoption::option_daily_stats_sse(&date).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::SzseDailyStats { date } => {
            let data = akoption::option_daily_stats_szse(&date).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexSz50ListSina => {
            let data = akoption::option_cffex_sz50_list_sina().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexSz50SpotSina { symbol } => {
            let data = akoption::option_cffex_sz50_spot_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexSz50DailySina { symbol } => {
            let data = akoption::option_cffex_sz50_daily_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexHs300ListSina => {
            let data = akoption::option_cffex_hs300_list_sina().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexHs300SpotSina { symbol } => {
            let data = akoption::option_cffex_hs300_spot_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexHs300DailySina { symbol } => {
            let data = akoption::option_cffex_hs300_daily_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexZz1000ListSina => {
            let data = akoption::option_cffex_zz1000_list_sina().await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexZz1000SpotSina { symbol } => {
            let data = akoption::option_cffex_zz1000_spot_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::CffexZz1000DailySina { symbol } => {
            let data = akoption::option_cffex_zz1000_daily_sina(&symbol).await?;
            println!("{}", serde_json::to_string_pretty(&data)?);
        }
        Commands::Db(db_cmd) => {
            handle_db_command(db_cmd).await?;
        }
    }
    Ok(())
}

async fn handle_db_command(cmd: DbCommands) -> Result<()> {
    use akoption::db::{DbConfig, OptionStore};
    use std::path::PathBuf;
    
    match cmd {
        DbCommands::Save { data_type, path } => {
            let config = get_db_config(path);
            let store = OptionStore::new(config).await?;
            
            match data_type {
                DataType::EmOptions => {
                    println!("获取东方财富期权数据...");
                    let data = akoption::option_current_em().await?;
                    println!("获取到 {} 条数据", data.len());
                    
                    println!("保存到数据库...");
                    store.save_em_options(&data).await?;
                    println!("✓ 保存成功");
                }
                DataType::ValueAnalysis => {
                    println!("获取价值分析数据...");
                    let data = akoption::option_value_analysis_em().await?;
                    println!("获取到 {} 条数据", data.len());
                    
                    println!("保存到数据库...");
                    store.save_value_analysis(&data).await?;
                    println!("✓ 保存成功");
                }
                DataType::RiskAnalysis => {
                    println!("获取风险分析数据...");
                    let data = akoption::option_risk_analysis_em().await?;
                    println!("获取到 {} 条数据", data.len());
                    
                    println!("保存到数据库...");
                    store.save_risk_analysis(&data).await?;
                    println!("✓ 保存成功");
                }
                DataType::SseContracts => {
                    println!("获取上交所合约到期月份...");
                    let data = akoption::option_sse_list_sina("50ETF").await?;
                    println!("获取到 {} 个到期月份", data.len());
                    
                    println!("保存到数据库...");
                    store.save_expire_dates(&data).await?;
                    println!("✓ 保存成功");
                }
            }
            
            println!("数据库路径: {}", store.config().path.display());
        }
        DbCommands::Query { data_type, code, path } => {
            let config = get_db_config(path);
            let store = OptionStore::new(config).await?;
            
            match data_type {
                DataType::EmOptions => {
                    let data = store.query_em_options(code.as_deref()).await?;
                    println!("{}", serde_json::to_string_pretty(&data)?);
                }
                DataType::ValueAnalysis => {
                    let data = store.query_value_analysis(code.as_deref()).await?;
                    println!("{}", serde_json::to_string_pretty(&data)?);
                }
                DataType::RiskAnalysis => {
                    let data = store.query_risk_analysis(code.as_deref()).await?;
                    println!("{}", serde_json::to_string_pretty(&data)?);
                }
                DataType::SseContracts => {
                    let data = store.query_sse_contracts(code.as_deref()).await?;
                    println!("{}", serde_json::to_string_pretty(&data)?);
                }
            }
        }
        DbCommands::Stats { path } => {
            let config = get_db_config(path);
            let store = OptionStore::new(config).await?;
            
            println!("=== 数据库统计 ===");
            println!("数据库路径: {}", store.config().path.display());
            println!();
            
            let tables = vec![
                ("em_options", "东方财富期权"),
                ("value_analysis", "价值分析"),
                ("risk_analysis", "风险分析"),
                ("sse_contracts", "上交所合约"),
            ];
            
            for (table, name) in tables {
                match store.count_records(table).await {
                    Ok(count) => println!("{}: {} 条", name, count),
                    Err(_) => println!("{}: 0 条", name),
                }
            }
        }
        DbCommands::Clear { table, path } => {
            let config = get_db_config(path);
            let store = OptionStore::new(config).await?;
            
            println!("清空表: {}", table);
            store.clear_table(&table).await?;
            println!("✓ 清空成功");
        }
    }
    
    Ok(())
}

fn get_db_config(path: Option<String>) -> akoption::db::DbConfig {
    use std::path::PathBuf;
    
    if let Some(p) = path {
        DbConfig::with_path(PathBuf::from(p))
    } else {
        DbConfig::default()
    }
}
